#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "matrix.h"

double determinant(double *matrix, int n, double shu) 
{   
    //复制一个和 matrix 一样的矩阵
    double *matrix_copy = (double *)malloc(n * n * sizeof(double));
    for (int i = 0; i < n * n; i++) 
	{
        matrix_copy[i] = matrix[i];
    } 
    double det = 1.0;
    int row_swap = 0; // 记录行交换次数
    for (int i = 0; i < n; i++) 
	{
        // 检查对角线元素是否为零，避免除零错误
        if (matrix_copy[i * n + i] == 0) 
		{
            int swap_row = -1;
            for (int k = i + 1; k < n; k++) 
			{
                if (matrix_copy[k * n + i] != 0)  //找到该元素下面行中第一个同列不为零元素的那一行，即令为 k
				{
                    swap_row = k;
                    break;
                }
            }
             // 无法找到非零元素，行列式为零
            if (swap_row == -1) 
			{ 
                free(matrix_copy);
                return 0.0;
            }
              //交换当前行和第 k+1 行
            for (int j = 0; j < n; j++) 
			{
                double temp = matrix_copy[i * n + j];
                matrix_copy[i * n + j] = matrix_copy[swap_row * n + j];
                matrix_copy[swap_row * n + j] = temp;
            }
            row_swap++; // 增加行交换次数
        }
          //利用高斯消元法 转换成 上三角矩阵
        for (int j = i + 1; j < n; j++) 
		{
            if (matrix_copy[j * n + i] != 0) 
			{
                double factor = matrix_copy[j * n + i] / matrix_copy[i * n + i];
                for (int k = i; k < n; k++) 
				{
                    matrix_copy[j * n + k] -= factor * matrix_copy[i * n + k];
                }
            }
        }
    }
    
   	int rank = 0;
    for (int i = 0; i < n; i++) {
        int nonzero = 0;
        for (int j = 0; j < n; j++) {
            if (matrix_copy[i * n + j] != 0) {
                nonzero = 1;
                break;
            }
        }
        if (nonzero) {
            rank++;
        }
    }
    // 计算利用对角线计算行列式
    for (int i = 0; i < n; i++) 
	{
        det *= matrix_copy[i * n + i];
    }
    // 如果行交换次数为奇数，行列式取反
    if (row_swap % 2 != 0) 
	{
        det = -det;
    }
    free(matrix_copy); //释放多余的 matrix_copy 的内存
    double result;
    if( shu == 5)
    {
    	result = det;
	}
	else if( shu == 6)
	{
		result = rank;
	}
    return result;
}



void inverse(double *matrix, int n, double shu) 
{
    double result = determinant(matrix, n, shu);
    if (result == 0) 
	{
        printf("大大，您输入的矩阵没有逆矩阵！！！");
        return;
    }
    printf("<5> 大大，您的逆矩阵是: \n");
    double *new1_matrix = (double *)malloc(n * n * sizeof(double));
    double *result_matrix = (double *)malloc(n * n * sizeof(double));
    for (int i = 0; i < n; i++) 
	{
        for (int j = 0; j < n; j++) 
		{
            int k = i + j;
            double *new_matrix = pass(matrix, n, i, j); //去掉第(i+1)行，第(j+1)列的新矩阵
            if (k % 2 == 0) 
			{  // k为偶数则为正
                new1_matrix[i * n + j] = determinant(new_matrix, n - 1, shu) / result;
            } 
			else 
			{  // k为奇数则为负数
                new1_matrix[i * n + j] = -determinant(new_matrix, n - 1, shu) / result;
            }
            free(new_matrix); // 释放子矩阵内存
        }
    }
    free(result_matrix); // 释放之前的内存
    result_matrix = transpose(new1_matrix, n, n); //转置
    for (int i = 0; i < n; i++) 
	{
        for (int j = 0; j < n; j++) 
		{
            printf("%.6lf  ", result_matrix[i * n + j]);
        }
        printf("\n");
    }
    free(new1_matrix); // 释放伴随矩阵内存
    free(result_matrix); // 释放转置矩阵内存
}

double *pass(double *matrix, int n, int a, int b) 
{
    int m = n - 1;
    double *matrix_2 = (double *)malloc(m * m * sizeof(double));
    if (matrix_2 == NULL) 
	{
        printf("内存分配失败 \n");
        exit(1);
    }
    int row_offset = 0, col_offset = 0;
    for (int i = 0; i < n; i++) 
	{
        if (i == a) 
		{
            row_offset = 1;
            continue;
        }        
        for (int j = 0; j < n; j++) 
		{
            if (j == b) 
			{
                col_offset = 1;
                continue;
            }
            int new_row = i - row_offset;
            int new_col = j - col_offset;
            matrix_2[new_row * m + new_col] = matrix[i * n + j];
        }
    }
    return matrix_2;
}